package com.example.dw.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.dw.common.ResultCode;
import com.example.dw.dto.*;
// import com.example.dw.entity.AboutMe;
import com.example.dw.entity.Pack;
import com.example.dw.entity.Sign;
import com.example.dw.entity.User;
// import com.example.dw.mapper.AboutMeMapper;
import com.example.dw.mapper.PackMapper;
import com.example.dw.mapper.SignMapper;
import com.example.dw.mapper.UserMapper;
import com.example.dw.service.UserService;
import com.example.dw.utils.JwtUtil;
import com.example.dw.utils.PasswordUtil;
import com.example.dw.utils.RedisUtil;
import com.example.dw.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 * @author system
 * @since 2024-01-01
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private SignMapper signMapper;

    // @Autowired
    // private AboutMeMapper aboutMeMapper;

    @Autowired
    private PackMapper packMapper;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private RedisUtil redisUtil;

    private static final String VERIFY_CODE_KEY = "verify_code:";
    private static final String QR_TOKEN_KEY = "qr_token:";
    private static final String QR_USER_KEY = "qr_user:";

    @Override
    public void register(UserRegisterDTO registerDTO) {
        // 验证两次密码是否一致
        if (!registerDTO.getPassword().equals(registerDTO.getConfirmPassword())) {
            throw new RuntimeException(ResultCode.PASSWORD_NOT_MATCH.getMessage());
        }

        // 检查用户名是否已存在
        User existUser = userMapper.findByUsername(registerDTO.getUsername());
        if (existUser != null) {
            throw new RuntimeException(ResultCode.USER_EXISTS.getMessage());
        }

        // 检查手机号是否已存在
        if (StrUtil.isNotBlank(registerDTO.getPhone())) {
            User phoneUser = userMapper.findByPhone(registerDTO.getPhone());
            if (phoneUser != null) {
                throw new RuntimeException(ResultCode.PHONE_EXISTS.getMessage());
            }
        }

        // 验证验证码（如果有提供）
        if (StrUtil.isNotBlank(registerDTO.getVerifyCode()) && StrUtil.isNotBlank(registerDTO.getPhone())) {
            String cachedCode = redisUtil.getString(VERIFY_CODE_KEY + registerDTO.getPhone());
            if (!registerDTO.getVerifyCode().equals(cachedCode)) {
                throw new RuntimeException(ResultCode.VERIFY_CODE_ERROR.getMessage());
            }
        }

        // 创建新用户
        User user = new User();
        user.setUsername(registerDTO.getUsername());
        user.setPassword(PasswordUtil.encode(registerDTO.getPassword()));
        user.setPhone(registerDTO.getPhone());
        user.setEmail(registerDTO.getEmail());
        user.setNickname(registerDTO.getNickname());
        user.setRole(0); // 默认学生角色
        user.setStatus(0); // 正常状态
        user.setDeleteStatus(0); // 未删除
        user.setCreateTime(LocalDateTime.now());
        user.setIntegral(0); // 初始积分为0

        save(user);

        // 删除验证码缓存
        if (StrUtil.isNotBlank(registerDTO.getPhone())) {
            redisUtil.delete(VERIFY_CODE_KEY + registerDTO.getPhone());
        }
    }

    @Override
    public Map<String, Object> login(UserLoginDTO loginDTO) {
        // 查找用户
        User user = userMapper.findByUsername(loginDTO.getUsername());
        if (user == null) {
            throw new RuntimeException(ResultCode.USER_NOT_FOUND.getMessage());
        }

        // 验证密码
        if (!PasswordUtil.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new RuntimeException(ResultCode.LOGIN_ERROR.getMessage());
        }

//        // 检查账号状态
//        if (user.getStatus() != 0) {
//            throw new RuntimeException(ResultCode.ACCOUNT_DISABLED.getMessage());
//        }

        // 生成token
        String token = jwtUtil.generateToken(user.getUserid(), user.getUsername());

        // 转换为VO
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);

        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("user", userVO);

        return result;
    }

    @Override
    public Map<String, Object> codeLogin(CodeLoginDTO codeLoginDTO) {
        // 验证验证码
        String cachedCode = redisUtil.getString(VERIFY_CODE_KEY + codeLoginDTO.getPhone());
        if (!codeLoginDTO.getCode().equals(cachedCode)) {
            throw new RuntimeException(ResultCode.VERIFY_CODE_ERROR.getMessage());
        }

        // 查找用户
        User user = userMapper.findByPhone(codeLoginDTO.getPhone());
        if (user == null) {
            throw new RuntimeException(ResultCode.USER_NOT_FOUND.getMessage());
        }

        // 检查账号状态
        if (user.getStatus() != 0) {
            throw new RuntimeException(ResultCode.ACCOUNT_DISABLED.getMessage());
        }

        // 生成token
        String token = jwtUtil.generateToken(user.getUserid(), user.getUsername());

        // 转换为VO
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);

        // 删除验证码缓存
        redisUtil.delete(VERIFY_CODE_KEY + codeLoginDTO.getPhone());

        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("user", userVO);

        return result;
    }

    @Override
    public Map<String, Object> wechatLogin(String code) {
        // TODO: 实现微信登录逻辑
        // 1. 通过code获取access_token
        // 2. 通过access_token获取用户信息
        // 3. 查找或创建用户
        // 4. 生成token返回
        throw new RuntimeException("微信登录功能待实现");
    }

    @Override
    public UserVO getUserInfo(Integer userid) {
        User user = getById(userid);
        if (user == null) {
            throw new RuntimeException(ResultCode.USER_NOT_FOUND.getMessage());
        }

        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);
        return userVO;
    }

    @Override
    public void updateUserInfo(Integer userid, UpdateUserInfoDTO updateUserInfoDTO) {
        User user = getById(userid);
        if (user == null) {
            throw new RuntimeException(ResultCode.USER_NOT_FOUND.getMessage());
        }

        // 检查手机号是否被其他用户使用
        if (StrUtil.isNotBlank(updateUserInfoDTO.getPhone()) && !updateUserInfoDTO.getPhone().equals(user.getPhone())) {
            User phoneUser = userMapper.findByPhone(updateUserInfoDTO.getPhone());
            if (phoneUser != null && !phoneUser.getUserid().equals(userid)) {
                throw new RuntimeException(ResultCode.PHONE_EXISTS.getMessage());
            }
        }

        // 更新用户信息
        User updateUser = new User();
        updateUser.setUserid(userid);
        BeanUtils.copyProperties(updateUserInfoDTO, updateUser);
        updateUser.setUpdateTime(LocalDateTime.now());

        updateById(updateUser);
    }

    @Override
    public void updatePassword(Integer userid, String oldPassword, String newPassword) {
        User user = getById(userid);
        if (user == null) {
            throw new RuntimeException(ResultCode.USER_NOT_FOUND.getMessage());
        }

        // 验证原密码
        if (!PasswordUtil.matches(oldPassword, user.getPassword())) {
            throw new RuntimeException(ResultCode.OLD_PASSWORD_ERROR.getMessage());
        }

        // 更新密码
        User updateUser = new User();
        updateUser.setUserid(userid);
        updateUser.setPassword(PasswordUtil.encode(newPassword));
        updateUser.setUpdateTime(LocalDateTime.now());

        updateById(updateUser);
    }

    @Override
    public void sign(Integer userid) {
        String today = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

        // 检查今日是否已签到
        Sign existSign = signMapper.findByUserIdAndDate(userid, today);
        if (existSign != null) {
            throw new RuntimeException(ResultCode.ALREADY_SIGNED_TODAY.getMessage());
        }

        // 创建签到记录
        Sign sign = new Sign();
        sign.setUserid(userid);
        sign.setSignDate(today);
        sign.setCreateAt(LocalTime.now());
        sign.setUpdateAt(LocalTime.now());

        signMapper.insert(sign);

        // 增加用户积分（签到+10分）
        User user = getById(userid);
        if (user != null) {
            user.setIntegral((user.getIntegral() != null ? user.getIntegral() : 0) + 10);
            updateById(user);
        }
    }

    @Override
    public Boolean signStatus(Integer userid) {
        String today = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        Sign sign = signMapper.findByUserIdAndDate(userid, today);
        return sign != null;
    }

    @Override
    public List<UserVO> getTeacherList() {
        List<User> teachers = userMapper.getTeacherList();
        return teachers.stream().map(teacher -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(teacher, userVO);
            return userVO;
        }).collect(Collectors.toList());
    }

    @Override
    public Map<String, Object> getTeacherListPage(Integer page, Integer size) {
        page = page != null && page > 0 ? page : 1;
        size = size != null && size > 0 ? size : 10;
        
        Integer offset = (page - 1) * size;
        List<User> teachers = userMapper.getTeacherListPage(offset, size);
        Integer total = userMapper.getTeacherCount();

        List<UserVO> teacherVOs = teachers.stream().map(teacher -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(teacher, userVO);
            return userVO;
        }).collect(Collectors.toList());

        Map<String, Object> result = new HashMap<>();
        result.put("list", teacherVOs);
        result.put("total", total);
        result.put("page", page);
        result.put("size", size);
        result.put("pages", (total + size - 1) / size);

        return result;
    }

    @Override
    public void bindPhone(Integer userid, String phone, String code) {
        // 验证验证码
        String cachedCode = redisUtil.getString(VERIFY_CODE_KEY + phone);
        if (!code.equals(cachedCode)) {
            throw new RuntimeException(ResultCode.VERIFY_CODE_ERROR.getMessage());
        }

        // 检查手机号是否已被其他用户使用
        User phoneUser = userMapper.findByPhone(phone);
        if (phoneUser != null && !phoneUser.getUserid().equals(userid)) {
            throw new RuntimeException(ResultCode.PHONE_EXISTS.getMessage());
        }

        // 更新用户手机号
        User updateUser = new User();
        updateUser.setUserid(userid);
        updateUser.setPhone(phone);
        updateUser.setUpdateTime(LocalDateTime.now());

        updateById(updateUser);

        // 删除验证码缓存
        redisUtil.delete(VERIFY_CODE_KEY + phone);
    }

    /*
    @Override
    public AboutMe getAboutMe() {
        return aboutMeMapper.getAboutMe();
    }
    */

    @Override
    public Pack getPack() {
        return packMapper.getPack();
    }

    @Override
    public void bindWechat(Integer userid, String code) {
        // TODO: 实现微信绑定逻辑
        throw new RuntimeException("微信绑定功能待实现");
    }

    @Override
    public Map<String, Object> getSignRecord(Integer userid, Integer page, Integer size) {
        page = page != null && page > 0 ? page : 1;
        size = size != null && size > 0 ? size : 10;
        
        Integer offset = (page - 1) * size;
        List<Sign> signs = signMapper.findByUserId(userid, offset, size);
        Integer total = signMapper.getSignCount(userid);

        Map<String, Object> result = new HashMap<>();
        result.put("list", signs);
        result.put("total", total);
        result.put("page", page);
        result.put("size", size);
        result.put("pages", (total + size - 1) / size);

        return result;
    }

    @Override
    public String generateLoginQR() {
        String qrToken = IdUtil.simpleUUID();
        // 设置二维码状态为待扫描，过期时间5分钟
        redisUtil.set(QR_TOKEN_KEY + qrToken, "waiting", 5, TimeUnit.MINUTES);
        return qrToken;
    }

    @Override
    public Map<String, Object> checkLoginStatus(String qrToken) {
        String status = redisUtil.getString(QR_TOKEN_KEY + qrToken);
        Map<String, Object> result = new HashMap<>();
        
        if (status == null) {
            result.put("status", "expired");
            result.put("message", "二维码已过期");
        } else if ("waiting".equals(status)) {
            result.put("status", "waiting");
            result.put("message", "等待扫码");
        } else if ("scanned".equals(status)) {
            result.put("status", "scanned");
            result.put("message", "已扫码，等待确认");
        } else if ("confirmed".equals(status)) {
            // 获取用户信息并生成token
            String useridStr = redisUtil.getString(QR_USER_KEY + qrToken);
            if (useridStr != null) {
                Integer userid = Integer.valueOf(useridStr);
                User user = getById(userid);
                if (user != null) {
                    String token = jwtUtil.generateToken(user.getUserid(), user.getUsername());
                    UserVO userVO = new UserVO();
                    BeanUtils.copyProperties(user, userVO);
                    
                    result.put("status", "success");
                    result.put("token", token);
                    result.put("user", userVO);
                    
                    // 清理缓存
                    redisUtil.delete(QR_TOKEN_KEY + qrToken);
                    redisUtil.delete(QR_USER_KEY + qrToken);
                }
            }
        }
        
        return result;
    }

    @Override
    public void bindScanToken(Integer userid, String qrToken) {
        String status = redisUtil.getString(QR_TOKEN_KEY + qrToken);
        if (status == null) {
            throw new RuntimeException("二维码已过期");
        }
        
        // 更新状态为已扫描
        redisUtil.set(QR_TOKEN_KEY + qrToken, "scanned", 5, TimeUnit.MINUTES);
        redisUtil.set(QR_USER_KEY + qrToken, userid.toString(), 5, TimeUnit.MINUTES);
    }

    @Override
    public void confirmScan(Integer userid, String qrToken) {
        String status = redisUtil.getString(QR_TOKEN_KEY + qrToken);
        if (status == null) {
            throw new RuntimeException("二维码已过期");
        }
        
        String useridStr = redisUtil.getString(QR_USER_KEY + qrToken);
        if (useridStr == null || !userid.toString().equals(useridStr)) {
            throw new RuntimeException("用户信息不匹配");
        }
        
        // 更新状态为已确认
        redisUtil.set(QR_TOKEN_KEY + qrToken, "confirmed", 1, TimeUnit.MINUTES);
    }
} 